String.prototype.escRegExp = function(){ return this.replace(/[\\$*+?()=!|,{}\[\]\.^]/g,'\\$&') }
String.prototype.unescHtml = function(){ var i,t=this; for(i in e) t=t.replace(new RegExp(i,'g'),e[i]); return t }
function Suggestions() { this.length=0; this.picked=0 }
var suggestions = new Suggestions()
var tagSearch='', lastEdit=''
var h={}, sections=[{},{},{},{},{},{}], selected={}, currentTag={}, e={'&lt;':'<','&gt;':'>','&amp;':'&','&quot;':'"'}

function init() { var elements = ['alpha','freq','rec','pop','copy','network'], divs={}, freqSort=[], freqMap={}, t,i
	for(i in elements) divs[elements[i]] = makeDiv(elements[i] + 'tags')
	elements = elements.concat('suggest','tags','yourtags','alphasort','freqsort')
	for(i in elements) h[elements[i]] = $id(elements[i])
	for(t in tags) {
		if (!freqMap[tags[t]]) { freqMap[tags[t]] = {}; freqSort[freqSort.length] = tags[t] }
		freqMap[tags[t]][t] = true;
		sections[0][t.toLowerCase()] = makeTag(divs.alpha, t, 'swap')
	}
	freqSort.sort(function(a,b){return b-a})
	for(i in freqSort) {
		for(t in freqMap[freqSort[i]]) {
			tagSearch += t + ' '
			sections[1][t.toLowerCase()] = makeTag(divs.freq, t, 'swap')
	}}
	for(t in copytags) { t = copytags[t]
		sections[4][t.toLowerCase()] = makeTag(divs.copy, t, 'swap')
		if(!sections[0][t]) tagSearch += t + ' '
	}
	if(copytags.length > 0) {
		$tag('span',h.copy).innerHTML = copyuser + "'s tags"
		h.copy.style.display = 'block'; h.copy.appendChild(divs.copy)
	}
	for(t in tagFor) { t = 'for:'+tagFor[t]
		sections[5][t.toLowerCase()] = makeTag(divs.network, t, 'swap')
		tagSearch += t + ' '
	}
	if(tagFor.length > 0) { h.network.style.display = 'block'; h.network.appendChild(divs.network) }
	for(t in tagPop) { t = tagPop[t]
		sections[2][t.toLowerCase()] = makeTag(divs.pop, t, 'swap')
		if(!sections[0][t.toLowerCase()] && !sections[4][t.toLowerCase()]) tagSearch += t + ' '
	}
	if(tagPop.length > 0) { h.pop.style.display = 'block'; h.pop.appendChild(divs.pop) }
	for(t in tagRec) { t = tagRec[t]
		sections[3][t.toLowerCase()] = makeTag(divs.rec, t, 'swap')
		for(i in sections) {
			if(sections[i][t.toLowerCase()]) { addClass(sections[i][t.toLowerCase()], 'recommended') }
	}}
	if(tagRec.length > 0) { h.rec.style.display = 'block'; h.rec.appendChild(divs.rec) }
	if(freqSort.length > 0) {
		h.yourtags.style.display = 'block'; h.freq.style.display = 'none'
		h.alpha.appendChild(divs.alpha); h.freq.appendChild(divs.freq)
	}
	document.onkeydown = document.onkeypress = document.onkeyup = handler
	updateHilight()
	if(window.Fold) Fold.go()
}

function makeDiv(id) { var obj=document.createElement('div'); obj.id=id; return obj }

function makeTag(parent, tag, js) {
	parent.appendChild(document.createTextNode(' '))
	var obj = document.createElement('a')
	obj.className = 'tag'
	obj.setAttribute('href','javascript:'+js+'("'+tag.replace(/"/g,'\\"')+'")')
	obj.appendChild(document.createTextNode(tag))
	if(tags[tag] < 2) obj.style.color = '#66f'
	if(tags[tag] == 2) obj.style.color = '#44f'
	parent.appendChild(obj)
	return obj
}

function select(t) { var i; t=t.toLowerCase()
	selected[t] = true; for(i in sections) if(sections[i][t]) addClass(sections[i][t], 'selected')
}
function deselect(t) { var i; t=t.toLowerCase()
	delete selected[t]; for(i in sections) if(sections[i][t]) rmClass(sections[i][t], 'selected')
}

function swap(tag){
	var tagArray = h.tags.value.trim().split(' '), present=false, t, tl=tag.toLowerCase()
	if (tagArray[0].trim() == '') tagArray.splice(0,1);
	for (t=0; t<tagArray.length; t++) {
		if (tagArray[t].toLowerCase() == tl) { tagArray.splice(t,1); deselect(tag); present=true; t-=1  }
	}
	if (!present) { tagArray.push(tag); select(tag) }
	var content = tagArray.join(' ')
	lastEdit = h.tags.value = (content.length > 1) ? content + ' ' : content
	hideSuggestions()
	focusTo(h.tags)
}

function complete(tag) { var tagArray=h.tags.value.split(' ')
	if(typeof tag == 'undefined') tag = suggestions[suggestions.picked].innerHTML.unescHtml() // tab complete rather than click complete
	tagArray[currentTag.index] = tag
	var text = tagArray.join(' ')
	h.tags.value = (text.substr(-1,1) == ' ' ? text : text + ' ' )
	hideSuggestions()
	updateHilight()
	focusTo(h.tags)
	$id("tags").blur();   //hack to "wake up" safari
	$id("tags").focus();
}

// focus the caret to end of a form input (+ optionally select some text)
var range=0 //ie
function focusTo(obj, selectFrom) {
	if (typeof selectFrom == 'undefined') selectFrom = obj.value.length
	if(obj.createTextRange){ //ie + opera
		if (range == 0) range = obj.createTextRange()
		range.moveEnd("character",obj.value.length)
		range.moveStart("character",selectFrom)
		//obj.select()
		//range.select()
		setTimeout('range.select()', 10)
	} else if (obj.setSelectionRange){ //ff
		obj.select()
		obj.setSelectionRange(selectFrom,obj.value.length)
	} else { //safari :(
	 obj.blur()
}}

function sort(text) { var lists=['alpha','freq'], l
	for(l in lists) { l = lists[l]
		h[l].style.display = (l == text) ? 'inline' : 'none'
		h[l + 'sort'].className = (l == text) ? 'noclicky' : 'clicky'
}}

function updateHilight() { var tagArray=h.tags.value.toLowerCase().split(' '), tagHash={}
	if (tagArray[0].trim() == '') tagArray.splice(0,1);
	for (t in tagArray) {
		if(tagArray[t] != '') {
			select(tagArray[t])
			tagHash[tagArray[t]] = true
	}}
	for (t in selected) {if (!tagHash[t]) deselect(t)}
	return [tagArray, tagHash]
}

function hideSuggestions() { h.suggest.parentNode.parentNode.style.visibility='hidden' }
function showSuggestions() { suggest(0); h.suggest.parentNode.parentNode.style.visibility='visible' }

function updateSuggestions() {
	if(!getCurrentTag() || !currentTag.text) { hideSuggestions(); return false }

	while (h.suggest.hasChildNodes()) h.suggest.removeChild(h.suggest.firstChild)
	delete suggestions; suggestions = new Suggestions();
	var tagArray = h.tags.value.toLowerCase().split(' '), txt=currentTag.text.escRegExp(), tagHash={}, t
	for(t in tagArray) tagHash[tagArray[t]] = true

	var search = tagSearch.match(new RegExp(("(?:^| )("+txt+"[^ ]+)"), "gi"))
	if(search){
		for (i=0; i<search.length && suggestions.length<10; i++) {
			tl = search[i].trim()
			if(tagHash[tl])  continue // do not suggest already typed tag
			suggestions[suggestions.length] = makeTag(h.suggest, tl, 'complete')
			suggestions.length++
	}}
	if (suggestions.length > 0) showSuggestions()
	else hideSuggestions()
}

function suggest(index) {
	if(suggestions.length == 1) index = 0
	if(suggestions[suggestions.picked]) suggestions[suggestions.picked].className = 'tag'
	suggestions[suggestions.picked = index].className = 'tag selected'
}

function getCurrentTag() {
	if(h.tags.value == lastEdit) return true // no edit
	if(h.tags == '') return false
	currentTag = {}
	var tagArray=h.tags.value.toLowerCase().split(' '), oldArray=lastEdit.toLowerCase().split(' '), currentTags = [], matched=false, t,o
	for (t in tagArray) {
		for (o in oldArray) {
			if(typeof oldArray[o] == 'undefined') { oldArray.splice(o,1); break }
			if(tagArray[t] == oldArray[o]) { matched = true; oldArray.splice(o,1); break; }
		}
		if(!matched) currentTags[currentTags.length] = t
		matched=false
	}
	// more than one word changed... abort
	if(currentTags.length > 1) { hideSuggestions(); return false }
	currentTag = { text:tagArray[currentTags[0]], index:currentTags[0] }
	return true
}

function handler(event) { var e=(event||window.event) //w3||ie
	if (e.type == 'keydown') {
		if(suggestions.length > 0) {
			switch(e.keyCode) {
				case 38: suggest((suggestions.picked + 1) % suggestions.length); break
				case 40: suggest(suggestions.picked == 0 ? suggestions.length - 1 : suggestions.picked - 1); break
				
	}}} else if (e.type == 'keypress') {
		switch(e.keyCode){
			case 38: case 40: 
				if(e.preventDefault && e.originalTarget) e.preventDefault() //ff
				break;
			case 9: // tab
				if (e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible') { //ff
					complete()
					e.preventDefault()
				}
				break;
			case 34432: //case 13: // enter
			if (h.suggest.parentNode.parentNode.style.visibility == 'hidden') {
				submitForm();
				} else {
			
				if (e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible') { //ff
					complete()
					e.preventDefault()
					
				}; 
				};
				
				return false;
				break;
			default: lastEdit = h.tags.value
	}} else if (e.type == 'keyup') {
		updateHilight()
		switch(e.keyCode) {
			//case 8:  //backspace
			//case 46: //delete
			case 35: //end
			case 36: //home
			case 39: // right
			case 37: // left
			case 32: // space
				hideSuggestions(); break
			case 38: case 40: break;
			case 9:
				if(!e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible') complete() //ie
				break;
			// case 1432234432: case 13:
			if (h.suggest.parentNode.parentNode.style.visibility == 'hidden') {
				} else {
				if(!e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible'){
					complete();
				};
				}
				
				return false;
				break;
			default: updateSuggestions()
}}}
function submitForm(){
document.forms.delForm.submit();
}





String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,'') }
String.prototype.unescHtml = function(){ var i,e={'&lt;':'<','&gt;':'>','&amp;':'&','&quot;':'"'},t=this; for(i in e) t=t.replace(new RegExp(i,'g'),e[i]); return t }

function loadTags(t) { tags = t }


// get previous/next non-text node
function previousElement(o) {
	if(o.previousSibling) { while (o.previousSibling.nodeType != 1) o = o.previousSibling; return o.previousSibling }
	else return false
}
function nextElement(o) {
	if(o.nextSibling) { while (o.nextSibling.nodeType != 1) o = o.nextSibling; return o.nextSibling }
	else return false
}

// styling functions
function isA(o,klass){ if(!o.className) return false; return new RegExp('\\b'+klass+'\\b').test(o.className) }
function addClass(o,klass){ if(!isA(o,klass)) o.className += ' ' + klass }
function rmClass(o,klass){ o.className = o.className.replace(new RegExp('\\s*\\b'+klass+'\\b'),'') }
function swapClass(o,klass,klass2){ var swap = isA(o,klass) ? [klass,klass2] : [klass2,klass]; rmClass(o,swap[0]); addClass(o,swap[1]) }
function getStyle(o,s) {
	if (document.defaultView && document.defaultView.getComputedStyle) return document.defaultView.getComputedStyle(o,null).getPropertyValue(s)
	else if (o.currentStyle) { return o.currentStyle[s.replace(/-([^-])/g, function(a,b){return b.toUpperCase()})] }
}
// shorter names for grabbing stuff
function $id(id){ return document.getElementById(id) }
function $tags(t,o){ o=o||document; return o.getElementsByTagName(t) }
function $tag(t,o,i) { o=o||document; return o.getElementsByTagName(t)[i||0] }
// get elements by class name, eg $c('post', document, 'li')
function $c(c,o,t) { o=o||document;
	if (!o.length) o = [o]
	else if(o.length == 1 && !o[0]) o = [o] // opera, you're weird
	var elements = []
	for(var i = 0, e; e = o[i]; i++) {
		if(e.getElementsByTagName) {
			var children = e.getElementsByTagName(t || '*')
			for (var j = 0, child; child = children[j]; j++) if(isA(child,c)) elements.push(child)
	}}
	return elements
}

